<script lang="ts">
	import { toast } from 'svelte-sonner';
	import { onMount, tick, getContext } from 'svelte';
	import { chatType, onlyGenerateImage, settings } from '$lib/stores';
	import { blobToFile, calculateSHA256, findWordIndices } from '$lib/utils';

	import Prompts from './MessageInput/PromptCommands.svelte';
	import Suggestions from './MessageInput/Suggestions.svelte';
	import { uploadDocToVectorDB, uploadWebToVectorDB } from '$lib/apis/rag';
	import AddFilesPlaceholder from '../AddFilesPlaceholder.svelte';
	import { SUPPORTED_FILE_TYPE, SUPPORTED_FILE_EXTENSIONS } from '$lib/constants';
	import Documents from './MessageInput/Documents.svelte';
	import Models from './MessageInput/Models.svelte';
	import { transcribeAudio } from '$lib/apis/audio';
	import Tooltip from '../common/Tooltip.svelte';
	import SendBtn from '../icons/SendBtn.svelte';
	import Stop from '../icons/Stop.svelte';
	import UploadImage from '../icons/UploadImage.svelte';
	import UploadFile from '../icons/UploadFile.svelte';
	import Sound from '../icons/Sound.svelte';
	import Loading from '../icons/Loading.svelte';

	const i18n = getContext('i18n');

	export let submitPrompt: Function;
	export let stopResponse: Function;

	export let suggestionPrompts = [];
	export let autoScroll = true;
	export let selectedModels = true;
	let chatTextAreaElement: HTMLTextAreaElement;
	let filesInputElement;

	let promptsElement;
	let documentsElement;
	let modelsElement;

	let inputFiles;
	let dragged = false;

	let user = null;
	let chatInputPlaceholder = '';

	export let files = [];

	// 文件上传开关
	export let fileUploadEnabled = false;
	//语音开关
	export let speechRecognitionEnabled = false;

	export let prompt = '';
	export let messages = [];

	let speechRecognition;

	$: if (prompt) {
		if (chatTextAreaElement) {
			chatTextAreaElement.style.height = '';
			chatTextAreaElement.style.height = Math.min(chatTextAreaElement.scrollHeight, 200) + 'px';
		}
	}

	let mediaRecorder;
	let audioChunks = [];
	let isRecording = false;
	const MIN_DECIBELS = -45;

	const imageGeneratePresets = [
		{
			title: '拉面',
			content: 'ultra detailed 8k cg, japanese ramen, chopsticks, egg, steam, boken'
		},
		{
			title: '飞船',
			content:
				'landscape, oil on matte canvas, sharp details, the expanse scifi spacescape ceres colony, intricate, highly detailed, digital painting, rich color, smooth, sharp focus, illustration, spaceship landed, Unreal Engine 5, 8K, art by artgerm and greg rutkowski and alphonse mucha'
		},
		{
			title: '跑车',
			content:
				"photo of a supercar, 8k uhd, high quality, road, sunset, motion blur, depth blur, cinematic, filmic image 4k, 8k with [George Miller's Mad Max style]. The image should be [ultra-realistic], with [high-resolution] captured in [natural light]. The lighting should create [soft shadows] and showcase the [raw] and [vibrant colors], volumetric dtx, depth blur, blurry background, bokeh, (motion blur:1.001)"
		},
		{
			title: '铠甲勇士',
			content:
				'cgmech, (realistic)solo, white mecha robot, cape, science fiction, torn clothes, glowing, standing, robot joints, mecha, armor, cowboy shot, (floating cape), intense sunlight, silver dragonborn, outdoors,landscape, nature, ((masterpiece, best quality)),  , volumetrics dtx, (film grain, blurry background, blurry foreground, bokeh, depth of field, motion blur:1.3)'
		},
		{
			title: '女孩',
			content:
				'8k portrait of beautiful cyborg with brown hair, intricate, elegant, highly detailed, majestic, digital photography, art by artgerm and ruan jia and greg rutkowski surreal painting gold butterfly filigree, broken glass, (masterpiece, sidelighting, finely detailed beautiful eyes: 1.2), hdr, (detailed background window to a new dimension, plants and flowers:0.7) infinity, infinite symbol'
		}
	];

	const scrollToBottom = () => {
		const element = document.getElementById('messages-container');
		element.scrollTop = element.scrollHeight;
	};

	const startRecording = async () => {
		const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
		mediaRecorder = new MediaRecorder(stream);
		mediaRecorder.onstart = () => {
			isRecording = true;
			console.log('Recording started');
		};
		mediaRecorder.ondataavailable = (event) => audioChunks.push(event.data);
		mediaRecorder.onstop = async () => {
			isRecording = false;
			console.log('Recording stopped');

			// Create a blob from the audio chunks
			const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });

			const file = blobToFile(audioBlob, 'recording.wav');

			const res = await transcribeAudio(localStorage.token, file).catch((error) => {
				toast.error(error);
				return null;
			});

			if (res) {
				prompt = res.text;
				await tick();
				chatTextAreaElement?.focus();

				if (prompt !== '' && $settings?.speechAutoSend === true) {
					submitPrompt(prompt, user);
				}
			}

			// saveRecording(audioBlob);
			audioChunks = [];
		};

		// Start recording
		mediaRecorder.start();

		// Monitor silence
		monitorSilence(stream);
	};

	const monitorSilence = (stream) => {
		const audioContext = new AudioContext();
		const audioStreamSource = audioContext.createMediaStreamSource(stream);
		const analyser = audioContext.createAnalyser();
		analyser.minDecibels = MIN_DECIBELS;
		audioStreamSource.connect(analyser);

		const bufferLength = analyser.frequencyBinCount;
		const domainData = new Uint8Array(bufferLength);

		let lastSoundTime = Date.now();

		const detectSound = () => {
			analyser.getByteFrequencyData(domainData);

			if (domainData.some((value) => value > 0)) {
				lastSoundTime = Date.now();
			}

			if (isRecording && Date.now() - lastSoundTime > 3000) {
				mediaRecorder.stop();
				audioContext.close();
				return;
			}

			window.requestAnimationFrame(detectSound);
		};

		window.requestAnimationFrame(detectSound);
	};

	const saveRecording = (blob) => {
		const url = URL.createObjectURL(blob);
		const a = document.createElement('a');
		document.body.appendChild(a);
		a.style = 'display: none';
		a.href = url;
		a.download = 'recording.wav';
		a.click();
		window.URL.revokeObjectURL(url);
	};

	const speechRecognitionHandler = () => {
		// Check if SpeechRecognition is supported

		if (isRecording) {
			if (speechRecognition) {
				speechRecognition.stop();
			}

			if (mediaRecorder) {
				mediaRecorder.stop();
			}
		} else {
			isRecording = true;

			if ($settings?.audio?.STTEngine ?? '' !== '') {
				startRecording();
			} else {
				if ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window) {
					// Create a SpeechRecognition object
					speechRecognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();

					// Set continuous to true for continuous recognition
					speechRecognition.continuous = true;

					// Set the timeout for turning off the recognition after inactivity (in milliseconds)
					const inactivityTimeout = 3000; // 3 seconds

					let timeoutId;
					// Start recognition
					speechRecognition.start();

					// Event triggered when speech is recognized
					speechRecognition.onresult = async (event) => {
						// Clear the inactivity timeout
						clearTimeout(timeoutId);

						// Handle recognized speech
						console.log(event);
						const transcript = event.results[Object.keys(event.results).length - 1][0].transcript;

						prompt = `${prompt}${transcript}`;

						await tick();
						chatTextAreaElement?.focus();

						// Restart the inactivity timeout
						timeoutId = setTimeout(() => {
							console.log('Speech recognition turned off due to inactivity.');
							speechRecognition.stop();
						}, inactivityTimeout);
					};

					// Event triggered when recognition is ended
					speechRecognition.onend = function () {
						// Restart recognition after it ends
						console.log('recognition ended');
						isRecording = false;
						if (prompt !== '' && $settings?.speechAutoSend === true) {
							submitPrompt(prompt, user);
						}
					};

					// Event triggered when an error occurs
					speechRecognition.onerror = function (event) {
						console.log(event);
						toast.error($i18n.t(`Speech recognition error: {{error}}`, { error: event.error }));
						isRecording = false;
					};
				} else {
					toast.error($i18n.t('SpeechRecognition API is not supported in this browser.'));
				}
			}
		}
	};

	const uploadDoc = async (file) => {
		console.log(file);

		const doc = {
			type: 'doc',
			name: file.name,
			size: file?.size,
			collection_name: '',
			upload_status: false,
			error: ''
		};

		try {
			files = [...files, doc];

			if (['audio/mpeg', 'audio/wav'].includes(file['type'])) {
				const res = await transcribeAudio(localStorage.token, file).catch((error) => {
					toast.error(error);
					return null;
				});

				// 语音类型只进行转换不创建对话
				if ($chatType === 'speech' && res) {
					console.log(res);
					doc.upload_status = true;
					doc.collection_name = res.text;
					doc.url = URL.createObjectURL(file);
					doc.type = 'speech';
					files = files;
					return;
				}

				if (res) {
					console.log(res);
					const blob = new Blob([res.text], { type: 'text/plain' });
					file = blobToFile(blob, `${file.name}.txt`);
				}
			}

			const res = await uploadDocToVectorDB(localStorage.token, '', file);

			if (res) {
				doc.upload_status = true;
				doc.collection_name = res.collection_name;
				files = files;
			}
		} catch (e) {
			// Remove the failed doc from the files array
			files = files.filter((f) => f.name !== file.name);
			toast.error(e);
		}
	};

	const uploadWeb = async (url) => {
		console.log(url);

		const doc = {
			type: 'doc',
			name: url,
			collection_name: '',
			upload_status: false,
			url: url,
			error: ''
		};

		try {
			files = [...files, doc];
			const res = await uploadWebToVectorDB(localStorage.token, '', url);

			if (res) {
				doc.upload_status = true;
				doc.collection_name = res.collection_name;
				files = files;
			}
		} catch (e) {
			// Remove the failed doc from the files array
			files = files.filter((f) => f.name !== url);
			toast.error(e);
		}
	};

	onMount(() => {
		window.setTimeout(() => chatTextAreaElement?.focus(), 0);

		// const dropZone = document.querySelector('body');
		const dropZone = document.getElementById('speech_input');

		const handleKeyDown = (event: KeyboardEvent) => {
			if (event.key === 'Escape') {
				console.log('Escape');
				dragged = false;
			}
		};

		const onDragOver = (e) => {
			e.preventDefault();
			dragged = true;
		};

		const onDragLeave = () => {
			dragged = false;
		};

		const onDrop = async (e) => {
			e.preventDefault();
			console.log(e);
			// if (!selectedModels?.[0]?.length) {
			// 	toast.error($i18n.t('Model not selected'));
			// 	dragged = false;
			// 	return;
			// }

			if (e.dataTransfer?.files) {
				let reader = new FileReader();

				reader.onload = (event) => {
					files = [
						...files,
						{
							type: 'image',
							url: `${event.target.result}`
						}
					];
				};

				const inputFiles = e.dataTransfer?.files;

				if (inputFiles && inputFiles.length > 0) {
					const file = inputFiles[0];
					if (!['audio/mpeg', 'audio/wav'].includes(file['type'])) {
						dragged = false;
						toast.error('不支持该文件格式');
						return;
					}
					console.log(file, file.name.split('.').at(-1));
					if (['image/gif', 'image/jpeg', 'image/png'].includes(file['type'])) {
						reader.readAsDataURL(file);
					} else if (
						SUPPORTED_FILE_TYPE.includes(file['type']) ||
						SUPPORTED_FILE_EXTENSIONS.includes(file.name.split('.').at(-1))
					) {
						uploadDoc(file);
					} else {
						toast.error(
							$i18n.t(
								`Unknown File Type '{{file_type}}', but accepting and treating as plain text`,
								{ file_type: file['type'] }
							)
						);
						uploadDoc(file);
					}
				} else {
					toast.error($i18n.t(`File not found.`));
				}
			}

			dragged = false;
		};

		window.addEventListener('keydown', handleKeyDown);

		dropZone?.addEventListener('dragover', onDragOver);
		dropZone?.addEventListener('drop', onDrop);
		dropZone?.addEventListener('dragleave', onDragLeave);

		return () => {
			window.removeEventListener('keydown', handleKeyDown);

			dropZone?.removeEventListener('dragover', onDragOver);
			dropZone?.removeEventListener('drop', onDrop);
			dropZone?.removeEventListener('dragleave', onDragLeave);
		};
	});
	console.log(files);
</script>

{#if dragged}
	<div
		class="fixed lg:w-[calc(100%-260px)] w-full h-full flex z-50 touch-none pointer-events-none"
		id="dropzone"
		role="region"
		aria-label="Drag and Drop Container"
	>
		<div class="absolute w-full h-full backdrop-blur bg-gray-800/40 flex justify-center">
			<div class="m-auto pt-64 flex flex-col justify-center">
				<div class="max-w-md">
					<AddFilesPlaceholder />
				</div>
			</div>
		</div>
	</div>
{/if}

<div class="w-full">
	<div class="px-3 {$chatType === 'speech' ? '' : 'hidden'}">
		{#if !files.length}
			<button
				id="speech_input"
				class="w-full max-w-3xl px-2.5 mx-auto mb-[50px] h-52 lg:h-[300px] bg-[#E955131A] flex flex-col justify-center items-center rounded-xl text-[#C5CBE0]"
				on:click={() => {
					filesInputElement.click();
				}}
			>
				<p class="text-[#B63D07]"><Sound /></p>
				<p class="mt-8 mb-1">点击选择语音文件，或者直接拖拽到这里</p>
				<p>支持格式：MP3/Wav</p>
			</button>
		{:else if !files?.[0]?.upload_status}
			<div
				id="speech_input"
				class="w-full max-w-3xl px-2.5 mx-auto mb-[50px] h-52 lg:h-[300px] bg-[#38D7A71A] flex flex-col justify-center items-center rounded-xl text-[#C5CBE0]"
			>
				<p class="text-[#38D7A7]"><Loading /></p>
				<p class="mt-6 text-[#38D7A7]">文件处理中...</p>
			</div>
		{/if}
	</div>
	<div class="px-3 {$chatType === 'speech' ? 'hidden' : ''}">
		<div class="px-2.5 -mb-0.5 mx-auto inset-x-0 bg-transparent flex justify-center">
			<div class="flex flex-col max-w-3xl w-full">
				<div class="relative">
					<!-- {#if autoScroll === false && messages.length > 0}
					<div class=" absolute -top-12 left-0 right-0 flex justify-center">
						<button
							class=" bg-white border border-gray-100 dark:border-none dark:bg-white/20 p-1.5 rounded-full"
							on:click={() => {
								autoScroll = true;
								scrollToBottom();
							}}
						>
							<svg
								xmlns="http://www.w3.org/2000/svg"
								viewBox="0 0 20 20"
								fill="currentColor"
								class="w-5 h-5"
							>
								<path
									fill-rule="evenodd"
									d="M10 3a.75.75 0 01.75.75v10.638l3.96-4.158a.75.75 0 111.08 1.04l-5.25 5.5a.75.75 0 01-1.08 0l-5.25-5.5a.75.75 0 111.08-1.04l3.96 4.158V3.75A.75.75 0 0110 3z"
									clip-rule="evenodd"
								/>
							</svg>
						</button>
					</div>
				{/if} -->
				</div>

				<div class="w-full relative">
					<!-- {#if prompt.charAt(0) === '/'}
					<Prompts bind:this={promptsElement} bind:prompt />
				{:else if prompt.charAt(0) === '#'}
					<Documents
						bind:this={documentsElement}
						bind:prompt
						on:url={(e) => {
							console.log(e);
							uploadWeb(e.detail);
						}}
						on:select={(e) => {
							console.log(e);
							files = [
								...files,
								{
									type: e?.detail?.type ?? 'doc',
									...e.detail,
									upload_status: true
								}
							];
						}}
					/>
				{:else if prompt.charAt(0) === '@'}
					<Models
						bind:this={modelsElement}
						bind:prompt
						bind:user
						bind:chatInputPlaceholder
						{messages}
					/>
				{/if} -->

					<!-- 默认提示词 -->
					<!-- {#if messages.length == 0 && suggestionPrompts.length !== 0}
					<Suggestions {suggestionPrompts} {submitPrompt} />
				{/if} -->
				</div>
			</div>
		</div>
		<div id="message-input">
			<div class="max-w-3xl px-2.5 mx-auto mb-[30px] inset-x-0 relative">
				{#if $onlyGenerateImage && (messages.length === 0 || messages.at(-1).done === true)}
					<div class="absolute z-20 -top-7 left-4">
						<span class="text-xs">试试这些：</span>
						{#each imageGeneratePresets as preset}
							<button
								class="px-2 py-0.5 rounded mr-2 text-sm bg-[#E9551380] hover:bg-[#E95513] transition-colors duration-300"
								on:click={() => {
									prompt = preset.content;
									chatTextAreaElement?.focus();
								}}>{preset.title}</button
							>
						{/each}
					</div>
				{/if}
				<div class=" pb-2">
					<input
						bind:this={filesInputElement}
						bind:files={inputFiles}
						type="file"
						accept={$chatType === 'picture'
							? 'image/*'
							: $chatType === 'speech'
							? 'audio/mpeg,audio/wav'
							: ''}
						hidden
						on:change={async () => {
							let reader = new FileReader();
							reader.onload = (event) => {
								files = [
									...files,
									{
										type: 'image',
										url: `${event.target.result}`
									}
								];
								inputFiles = null;
								filesInputElement.value = '';
							};

							if (inputFiles && inputFiles.length > 0) {
								const file = inputFiles[0];
								if (['image/gif', 'image/jpeg', 'image/png'].includes(file['type'])) {
									reader.readAsDataURL(file);
								} else if (
									SUPPORTED_FILE_TYPE.includes(file['type']) ||
									SUPPORTED_FILE_EXTENSIONS.includes(file.name.split('.').at(-1))
								) {
									uploadDoc(file);
									filesInputElement.value = '';
								} else {
									toast.error(
										$i18n.t(
											`Unknown File Type '{{file_type}}', but accepting and treating as plain text`,
											{ file_type: file['type'] }
										)
									);
									uploadDoc(file);
									filesInputElement.value = '';
								}
							} else {
								toast.error($i18n.t(`File not found.`));
							}
						}}
					/>
					<form
						class=" flex flex-col relative w-full rounded-xl bg-[#37424B]"
						on:submit|preventDefault={() => {
							submitPrompt(prompt, user);
						}}
					>
						<!-- {#if files.length > 0}
						<div class="mx-2 mt-2 mb-1 flex flex-wrap gap-2">
							{#each files as file, fileIdx}
								<div class=" relative group">
									{#if file.type === 'image'}
										<img src={file.url} alt="input" class=" h-16 w-16 rounded-xl object-cover" />
									{:else if file.type === 'doc'}
										<div
											class="h-16 w-[15rem] flex items-center space-x-3 px-2.5 dark:bg-gray-600 rounded-xl border border-gray-200 dark:border-none"
										>
											<div class="p-2.5 bg-red-400 text-white rounded-lg">
												{#if file.upload_status}
													<svg
														xmlns="http://www.w3.org/2000/svg"
														viewBox="0 0 24 24"
														fill="currentColor"
														class="w-6 h-6"
													>
														<path
															fill-rule="evenodd"
															d="M5.625 1.5c-1.036 0-1.875.84-1.875 1.875v17.25c0 1.035.84 1.875 1.875 1.875h12.75c1.035 0 1.875-.84 1.875-1.875V12.75A3.75 3.75 0 0 0 16.5 9h-1.875a1.875 1.875 0 0 1-1.875-1.875V5.25A3.75 3.75 0 0 0 9 1.5H5.625ZM7.5 15a.75.75 0 0 1 .75-.75h7.5a.75.75 0 0 1 0 1.5h-7.5A.75.75 0 0 1 7.5 15Zm.75 2.25a.75.75 0 0 0 0 1.5H12a.75.75 0 0 0 0-1.5H8.25Z"
															clip-rule="evenodd"
														/>
														<path
															d="M12.971 1.816A5.23 5.23 0 0 1 14.25 5.25v1.875c0 .207.168.375.375.375H16.5a5.23 5.23 0 0 1 3.434 1.279 9.768 9.768 0 0 0-6.963-6.963Z"
														/>
													</svg>
												{:else}
													<svg
														class=" w-6 h-6 translate-y-[0.5px]"
														fill="currentColor"
														viewBox="0 0 24 24"
														xmlns="http://www.w3.org/2000/svg"
														><style>
															.spinner_qM83 {
																animation: spinner_8HQG 1.05s infinite;
															}
															.spinner_oXPr {
																animation-delay: 0.1s;
															}
															.spinner_ZTLf {
																animation-delay: 0.2s;
															}
															@keyframes spinner_8HQG {
																0%,
																57.14% {
																	animation-timing-function: cubic-bezier(0.33, 0.66, 0.66, 1);
																	transform: translate(0);
																}
																28.57% {
																	animation-timing-function: cubic-bezier(0.33, 0, 0.66, 0.33);
																	transform: translateY(-6px);
																}
																100% {
																	transform: translate(0);
																}
															}
														</style><circle class="spinner_qM83" cx="4" cy="12" r="2.5" /><circle
															class="spinner_qM83 spinner_oXPr"
															cx="12"
															cy="12"
															r="2.5"
														/><circle
															class="spinner_qM83 spinner_ZTLf"
															cx="20"
															cy="12"
															r="2.5"
														/></svg
													>
												{/if}
											</div>

											<div class="flex flex-col justify-center -space-y-0.5">
												<div class=" dark:text-gray-100 text-sm font-medium line-clamp-1">
													{file.name}
												</div>

												<div class=" text-gray-500 text-sm">{$i18n.t('Document')}</div>
											</div>
										</div>
									{:else if file.type === 'collection'}
										<div
											class="h-16 w-[15rem] flex items-center space-x-3 px-2.5 dark:bg-gray-600 rounded-xl border border-gray-200 dark:border-none"
										>
											<div class="p-2.5 bg-red-400 text-white rounded-lg">
												<svg
													xmlns="http://www.w3.org/2000/svg"
													viewBox="0 0 24 24"
													fill="currentColor"
													class="w-6 h-6"
												>
													<path
														d="M7.5 3.375c0-1.036.84-1.875 1.875-1.875h.375a3.75 3.75 0 0 1 3.75 3.75v1.875C13.5 8.161 14.34 9 15.375 9h1.875A3.75 3.75 0 0 1 21 12.75v3.375C21 17.16 20.16 18 19.125 18h-9.75A1.875 1.875 0 0 1 7.5 16.125V3.375Z"
													/>
													<path
														d="M15 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 17.25 7.5h-1.875A.375.375 0 0 1 15 7.125V5.25ZM4.875 6H6v10.125A3.375 3.375 0 0 0 9.375 19.5H16.5v1.125c0 1.035-.84 1.875-1.875 1.875h-9.75A1.875 1.875 0 0 1 3 20.625V7.875C3 6.839 3.84 6 4.875 6Z"
													/>
												</svg>
											</div>

											<div class="flex flex-col justify-center -space-y-0.5">
												<div class=" dark:text-gray-100 text-sm font-medium line-clamp-1">
													{file?.title ?? `#${file.name}`}
												</div>

												<div class=" text-gray-500 text-sm">{$i18n.t('Collection')}</div>
											</div>
										</div>
									{/if}

									<div class=" absolute -top-1 -right-1">
										<button
											class=" bg-gray-400 text-white border border-white rounded-full group-hover:visible invisible transition"
											type="button"
											on:click={() => {
												files.splice(fileIdx, 1);
												files = files;
											}}
										>
											<svg
												xmlns="http://www.w3.org/2000/svg"
												viewBox="0 0 20 20"
												fill="currentColor"
												class="w-4 h-4"
											>
												<path
													d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
												/>
											</svg>
										</button>
									</div>
								</div>
							{/each}
						</div>
					{/if} -->

						<div class=" flex">
							<!-- {#if fileUploadEnabled}
							<div class=" self-end mb-2 ml-1">
								<Tooltip content={$i18n.t('Upload files')}>
									<button
										class="bg-gray-50 hover:bg-gray-100 text-gray-800 dark:bg-gray-850 dark:text-white dark:hover:bg-gray-800 transition rounded-full p-1.5"
										type="button"
										on:click={() => {
											filesInputElement.click();
										}}
									>
										<svg
											xmlns="http://www.w3.org/2000/svg"
											viewBox="0 0 16 16"
											fill="currentColor"
											class="w-[1.2rem] h-[1.2rem]"
										>
											<path
												d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z"
											/>
										</svg>
									</button>
								</Tooltip>
							</div>
						{/if} -->
							<div class="p-[15px_0_15px_15px] flex-none">
								{#if files.length > 0}
									{#each files as file, fileIdx}
										<div class=" relative group">
											{#if file.type === 'image'}
												<img
													src={file.url}
													alt="input"
													class="h-[70px] w-[70px] rounded-xl object-cover"
												/>
											{:else if file.type === 'doc'}
												<div
													class="h-16 w-[10rem] flex items-center space-x-3 px-2.5 rounded-xl bg-[#E9551333]"
												>
													<div class="text-[#E95513]">
														{#if file.upload_status}
															<svg
																xmlns="http://www.w3.org/2000/svg"
																viewBox="0 0 24 24"
																fill="currentColor"
																class="w-10 h-10"
															>
																<path
																	fill-rule="evenodd"
																	d="M5.625 1.5c-1.036 0-1.875.84-1.875 1.875v17.25c0 1.035.84 1.875 1.875 1.875h12.75c1.035 0 1.875-.84 1.875-1.875V12.75A3.75 3.75 0 0 0 16.5 9h-1.875a1.875 1.875 0 0 1-1.875-1.875V5.25A3.75 3.75 0 0 0 9 1.5H5.625ZM7.5 15a.75.75 0 0 1 .75-.75h7.5a.75.75 0 0 1 0 1.5h-7.5A.75.75 0 0 1 7.5 15Zm.75 2.25a.75.75 0 0 0 0 1.5H12a.75.75 0 0 0 0-1.5H8.25Z"
																	clip-rule="evenodd"
																/>
																<path
																	d="M12.971 1.816A5.23 5.23 0 0 1 14.25 5.25v1.875c0 .207.168.375.375.375H16.5a5.23 5.23 0 0 1 3.434 1.279 9.768 9.768 0 0 0-6.963-6.963Z"
																/>
															</svg>
														{:else}
															<svg
																class=" w-10 h-10 translate-y-[0.5px]"
																fill="currentColor"
																viewBox="0 0 24 24"
																xmlns="http://www.w3.org/2000/svg"
																><style>
																	.spinner_qM83 {
																		animation: spinner_8HQG 1.05s infinite;
																	}
																	.spinner_oXPr {
																		animation-delay: 0.1s;
																	}
																	.spinner_ZTLf {
																		animation-delay: 0.2s;
																	}
																	@keyframes spinner_8HQG {
																		0%,
																		57.14% {
																			animation-timing-function: cubic-bezier(0.33, 0.66, 0.66, 1);
																			transform: translate(0);
																		}
																		28.57% {
																			animation-timing-function: cubic-bezier(0.33, 0, 0.66, 0.33);
																			transform: translateY(-6px);
																		}
																		100% {
																			transform: translate(0);
																		}
																	}
																</style><circle
																	class="spinner_qM83"
																	cx="4"
																	cy="12"
																	r="2.5"
																/><circle
																	class="spinner_qM83 spinner_oXPr"
																	cx="12"
																	cy="12"
																	r="2.5"
																/><circle
																	class="spinner_qM83 spinner_ZTLf"
																	cx="20"
																	cy="12"
																	r="2.5"
																/></svg
															>
														{/if}
													</div>

													<div class="flex flex-col justify-center -space-y-0.5">
														<div class="text-[#F7F7F7] text-sm font-medium line-clamp-1">
															{file.name}
														</div>

														<div class="text-[#C5CBE0] text-xs">{$i18n.t('Document')}</div>
													</div>
												</div>
											{:else if file.type === 'collection'}
												<div
													class="h-16 w-[10rem] flex items-center space-x-3 px-2.5 rounded-xl bg-[#E9551333]"
												>
													<div class="text-[#E95513]">
														<svg
															xmlns="http://www.w3.org/2000/svg"
															viewBox="0 0 24 24"
															fill="currentColor"
															class="w-10 h-10"
														>
															<path
																d="M7.5 3.375c0-1.036.84-1.875 1.875-1.875h.375a3.75 3.75 0 0 1 3.75 3.75v1.875C13.5 8.161 14.34 9 15.375 9h1.875A3.75 3.75 0 0 1 21 12.75v3.375C21 17.16 20.16 18 19.125 18h-9.75A1.875 1.875 0 0 1 7.5 16.125V3.375Z"
															/>
															<path
																d="M15 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 17.25 7.5h-1.875A.375.375 0 0 1 15 7.125V5.25ZM4.875 6H6v10.125A3.375 3.375 0 0 0 9.375 19.5H16.5v1.125c0 1.035-.84 1.875-1.875 1.875h-9.75A1.875 1.875 0 0 1 3 20.625V7.875C3 6.839 3.84 6 4.875 6Z"
															/>
														</svg>
													</div>

													<div class="flex flex-col justify-center -space-y-0.5">
														<div class=" text-[#F7F7F7] text-sm font-medium line-clamp-1">
															{file?.title ?? `#${file.name}`}
														</div>

														<div class=" text-[#C5CBE0] text-xs">{$i18n.t('Collection')}</div>
													</div>
												</div>
											{/if}

											<div class=" absolute -top-1 -right-1">
												<button
													class=" bg-[#EB5757] text-white rounded-full group-hover:visible invisible transition"
													type="button"
													on:click={() => {
														files.splice(fileIdx, 1);
														files = files;
													}}
												>
													<svg
														xmlns="http://www.w3.org/2000/svg"
														viewBox="0 0 20 20"
														fill="currentColor"
														class="w-5 h-5"
													>
														<path
															d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
														/>
													</svg>
												</button>
											</div>
										</div>
									{/each}
								{:else if $chatType === 'picture' && !$onlyGenerateImage}
									<Tooltip content={$i18n.t('Upload files')}>
										<button
											type="button"
											on:click={() => {
												filesInputElement.click();
											}}
										>
											<UploadImage />
										</button>
									</Tooltip>
								{:else if $chatType === 'rag'}
									<Tooltip content={$i18n.t('Upload files')}>
										<button
											type="button"
											on:click={() => {
												filesInputElement.click();
											}}
										>
											<UploadFile />
										</button>
									</Tooltip>
								{/if}
							</div>

							<textarea
								id="chat-textarea"
								bind:this={chatTextAreaElement}
								class=" bg-[#37424B] text-[#F7F7F7] outline-none w-full p-[10px] {fileUploadEnabled
									? ''
									: ' pl-4'} placeholder:text=[#858EAD] rounded-xl resize-none h-[100px]"
								placeholder={chatInputPlaceholder !== ''
									? chatInputPlaceholder
									: isRecording
									? $i18n.t('Listening...')
									: // : $i18n.t('Send a Message')}
									  '在这里输入问题\n按下 Shift + Enter 换行'}
								bind:value={prompt}
								on:keypress={(e) => {
									if (e.keyCode == 13 && !e.shiftKey) {
										e.preventDefault();
									}
									if (prompt !== '' && e.keyCode == 13 && !e.shiftKey) {
										submitPrompt(prompt, user);
									}
								}}
								on:keydown={async (e) => {
									const isCtrlPressed = e.ctrlKey || e.metaKey; // metaKey is for Cmd key on Mac

									// Check if Ctrl + R is pressed
									if (prompt === '' && isCtrlPressed && e.key.toLowerCase() === 'r') {
										e.preventDefault();
										console.log('regenerate');

										const regenerateButton = [
											...document.getElementsByClassName('regenerate-response-button')
										]?.at(-1);

										regenerateButton?.click();
									}

									if (prompt === '' && e.key == 'ArrowUp') {
										e.preventDefault();

										const userMessageElement = [
											...document.getElementsByClassName('user-message')
										]?.at(-1);

										const editButton = [
											...document.getElementsByClassName('edit-user-message-button')
										]?.at(-1);

										console.log(userMessageElement);

										userMessageElement.scrollIntoView({ block: 'center' });
										editButton?.click();
									}

									if (['/', '#', '@'].includes(prompt.charAt(0)) && e.key === 'ArrowUp') {
										e.preventDefault();

										(promptsElement || documentsElement || modelsElement).selectUp();

										const commandOptionButton = [
											...document.getElementsByClassName('selected-command-option-button')
										]?.at(-1);
										commandOptionButton.scrollIntoView({ block: 'center' });
									}

									if (['/', '#', '@'].includes(prompt.charAt(0)) && e.key === 'ArrowDown') {
										e.preventDefault();

										(promptsElement || documentsElement || modelsElement).selectDown();

										const commandOptionButton = [
											...document.getElementsByClassName('selected-command-option-button')
										]?.at(-1);
										commandOptionButton.scrollIntoView({ block: 'center' });
									}

									if (['/', '#', '@'].includes(prompt.charAt(0)) && e.key === 'Enter') {
										e.preventDefault();

										const commandOptionButton = [
											...document.getElementsByClassName('selected-command-option-button')
										]?.at(-1);

										commandOptionButton?.click();
									}

									if (['/', '#', '@'].includes(prompt.charAt(0)) && e.key === 'Tab') {
										e.preventDefault();

										const commandOptionButton = [
											...document.getElementsByClassName('selected-command-option-button')
										]?.at(-1);

										commandOptionButton?.click();
									} else if (e.key === 'Tab') {
										const words = findWordIndices(prompt);

										if (words.length > 0) {
											const word = words.at(0);
											const fullPrompt = prompt;

											prompt = prompt.substring(0, word?.endIndex + 1);
											await tick();

											e.target.scrollTop = e.target.scrollHeight;
											prompt = fullPrompt;
											await tick();

											e.preventDefault();
											e.target.setSelectionRange(word?.startIndex, word.endIndex + 1);
										}
									}
								}}
								rows="1"
								on:input={(e) => {
									e.target.style.height = '';
									e.target.style.height = Math.min(e.target.scrollHeight, 100) + 'px';
									user = null;
								}}
								on:focus={(e) => {
									e.target.style.height = '';
									e.target.style.height = Math.min(e.target.scrollHeight, 100) + 'px';
								}}
								on:paste={(e) => {
									const clipboardData = e.clipboardData || window.clipboardData;

									if (clipboardData && clipboardData.items) {
										for (const item of clipboardData.items) {
											if (item.type.indexOf('image') !== -1) {
												const blob = item.getAsFile();
												const reader = new FileReader();

												reader.onload = function (e) {
													files = [
														...files,
														{
															type: 'image',
															url: `${e.target.result}`
														}
													];
												};

												reader.readAsDataURL(blob);
											}
										}
									}
								}}
							/>

							<div class="self-end mb-2 flex space-x-1 mr-1">
								<!-- {#if messages.length == 0 || messages.at(-1).done == true} -->
								<Tooltip content={$i18n.t('Record voice')}>
									{#if speechRecognitionEnabled}
										<button
											id="voice-input-button"
											class=" text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-850 transition rounded-full p-1.5 mr-0.5 self-center"
											type="button"
											on:click={() => {
												speechRecognitionHandler();
											}}
										>
											{#if isRecording}
												<svg
													class=" w-5 h-5 translate-y-[0.5px]"
													fill="currentColor"
													viewBox="0 0 24 24"
													xmlns="http://www.w3.org/2000/svg"
													><style>
														.spinner_qM83 {
															animation: spinner_8HQG 1.05s infinite;
														}
														.spinner_oXPr {
															animation-delay: 0.1s;
														}
														.spinner_ZTLf {
															animation-delay: 0.2s;
														}
														@keyframes spinner_8HQG {
															0%,
															57.14% {
																animation-timing-function: cubic-bezier(0.33, 0.66, 0.66, 1);
																transform: translate(0);
															}
															28.57% {
																animation-timing-function: cubic-bezier(0.33, 0, 0.66, 0.33);
																transform: translateY(-6px);
															}
															100% {
																transform: translate(0);
															}
														}
													</style><circle class="spinner_qM83" cx="4" cy="12" r="2.5" /><circle
														class="spinner_qM83 spinner_oXPr"
														cx="12"
														cy="12"
														r="2.5"
													/><circle
														class="spinner_qM83 spinner_ZTLf"
														cx="20"
														cy="12"
														r="2.5"
													/></svg
												>
											{:else}
												<svg
													xmlns="http://www.w3.org/2000/svg"
													viewBox="0 0 20 20"
													fill="currentColor"
													class="w-5 h-5 translate-y-[0.5px]"
												>
													<path d="M7 4a3 3 0 016 0v6a3 3 0 11-6 0V4z" />
													<path
														d="M5.5 9.643a.75.75 0 00-1.5 0V10c0 3.06 2.29 5.585 5.25 5.954V17.5h-1.5a.75.75 0 000 1.5h4.5a.75.75 0 000-1.5h-1.5v-1.546A6.001 6.001 0 0016 10v-.357a.75.75 0 00-1.5 0V10a4.5 4.5 0 01-9 0v-.357z"
													/>
												</svg>
											{/if}
										</button>
									{/if}
								</Tooltip>

								<Tooltip content={$i18n.t('Send message')}>
									<!-- class="{prompt !== ''
											? 'bg-black text-white hover:bg-gray-900 dark:bg-white dark:text-black dark:hover:bg-gray-100 '
											: 'text-white bg-gray-100 dark:text-gray-900 dark:bg-gray-800 disabled'} transition rounded-full p-1.5 self-center" -->
									<button
										class="text-[#E9551380] hover:text-[#E95513]"
										type="submit"
										disabled={prompt === ''}
									>
										<SendBtn />
										<!-- <svg
											xmlns="http://www.w3.org/2000/svg"
											viewBox="0 0 16 16"
											fill="currentColor"
											class="w-5 h-5"
										>
											<path
												fill-rule="evenodd"
												d="M8 14a.75.75 0 0 1-.75-.75V4.56L4.03 7.78a.75.75 0 0 1-1.06-1.06l4.5-4.5a.75.75 0 0 1 1.06 0l4.5 4.5a.75.75 0 0 1-1.06 1.06L8.75 4.56v8.69A.75.75 0 0 1 8 14Z"
												clip-rule="evenodd"
											/>
										</svg> -->
									</button>
								</Tooltip>
								<!-- {:else} -->
								<!-- 停止 -->
								<!-- <button
									class="bg-white hover:bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-800 transition rounded-full p-1.5"
									on:click={stopResponse}
								>
									<svg
										xmlns="http://www.w3.org/2000/svg"
										viewBox="0 0 24 24"
										fill="currentColor"
										class="w-5 h-5"
									>
										<path
											fill-rule="evenodd"
											d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12zm6-2.438c0-.724.588-1.312 1.313-1.312h4.874c.725 0 1.313.588 1.313 1.313v4.874c0 .725-.588 1.313-1.313 1.313H9.564a1.312 1.312 0 01-1.313-1.313V9.564z"
											clip-rule="evenodd"
										/>
									</svg>
								</button>
							{/if} -->
							</div>

							<!-- 停止 -->
							{#if messages.length !== 0 && messages.at(-1).done !== true}
								<button
									class="flex absolute -top-11 left-1/2 -translate-x-1/2 justify-center items-center h-9 bg-[#F2994A33] text-[#F2994A] rounded-[5px] px-4"
									on:click={stopResponse}
								>
									<Stop />
									<span class="ml-2">停止回答</span>
								</button>
							{/if}
						</div>
					</form>

					<!-- <div class="mt-1.5 text-xs text-gray-500 text-center">
					{$i18n.t('LLMs can make mistakes. Verify important information.')}
				</div> -->
				</div>
			</div>
		</div>
	</div>
</div>
